
#if	!defined( __20081116_DEF_WINSOCKIPV4_H__ )
#define	__20081116_DEF_WINSOCKIPV4_H__

namespace PCE_Lib {
namespace CEnv_Def {
namespace PCE_Lib_CurrentCEnvironment {
namespace Tools {

class WinSockIPv4 : public IPv4
{
public:
	typedef	IPv4	inherited;
protected:
	class IPv4SyncConnection : public SyncConnection
	{
		friend class WinSockIPv4;
	public:
		typedef	SyncConnection	inherited;
	public:
		virtual bool Send( const void * buff, usize_t len ) throw()
		{
			assert( NULL != buff );
			assert( len > 0 );
			assert( INVALID_SOCKET != m_Socket );

			int32_t			ret_code, remain_len = int32_t( len );
			const char_t	* cur_buff = ( const char_t * )buff;
			do {
				ret_code = send( m_Socket, cur_buff, remain_len, 0 );
				if( SOCKET_ERROR == ret_code ) {
					Close();	// something is wrong
					m_IsFail = true;
					return false;
				}
				assert( ret_code > 0 );
				assert( ret_code <= remain_len );
				remain_len -= ret_code;
				cur_buff += ret_code;
			}while( remain_len > 0 );

			m_IsFail = false;
			return true;
		}
		virtual usize_t Receive( void * buff, usize_t len ) throw()
		{
			assert( NULL != buff );
			assert( len > 0 );
			assert( INVALID_SOCKET != m_Socket );

			int32_t	ret_code = recv( m_Socket, (char_t *)buff, int32_t( len ), 0 );
			switch( ret_code ) {
			case 0:				// connection is closed
				m_IsFail = ! Close();
				return 0;
			case SOCKET_ERROR:	// something is wrong
				Close();
				m_IsFail = true;
				return 0;
			default:			// ok
				assert( ret_code > 0 );
				m_IsFail = false;
				return usize_t( ret_code );
			}
		}
		virtual bool IsOpen( void ) throw()
		{
			return INVALID_SOCKET != m_Socket;
		}
		virtual bool IsFail( void ) throw() { return m_IsFail; }
	protected:
		bool Close( void ) throw()
		{
			bool ret_val = true;

			if( m_IsOwn && (INVALID_SOCKET != m_Socket) ) {
				ret_val = (0 == closesocket( m_Socket ));
			}
			m_Socket = INVALID_SOCKET;
			m_IsOwn = false;
			m_IsFail = false;
			return ret_val;
		}
		void Set( SOCKET sock, bool is_own ) throw()
		{
			m_Socket = sock;
			m_IsOwn = is_own;
			m_IsFail = false;
		}
	public:
		IPv4SyncConnection( void ) throw() : inherited(),
			m_Socket( INVALID_SOCKET ), m_IsOwn( false ), m_IsFail( false )
		{}
		virtual ~IPv4SyncConnection( void ) throw() { Close(); }
	protected:
		SOCKET	m_Socket;
		bool	m_IsOwn;
		bool	m_IsFail;
	};
protected:
	static void sif_SetSynConnection( IPv4SyncConnection & conn, SOCKET sock, bool is_own ) throw()
	{
		conn.Set( sock, is_own );
	}
protected:
	WinSockIPv4( void ) throw() : inherited(), m_WinSockInit() {}
public:
	virtual ~WinSockIPv4( void ) throw() {}
private:
	WinSockInit		m_WinSockInit;
};

class WinSockIPv4Client : public WinSockIPv4
{
public:
	typedef	WinSockIPv4	inherited;
protected:
	bool if_OpenSyn( const char_t * addr, uint16_t port ) throw()
	{
		assert( NULL != addr );

		sockaddr_in		client_addr;

		if( ! Close() ) {
			return false;
		}
		// create socket
		m_Socket = socket( AF_INET, SOCK_STREAM, 0 );
		if( INVALID_SOCKET == m_Socket ) {
			return false;
		}
		// connect
		client_addr.sin_family = AF_INET;
		client_addr.sin_addr.s_addr = inet_addr( addr );
		client_addr.sin_port = htons( port );
		if( SOCKET_ERROR == connect( m_Socket, (SOCKADDR*) & client_addr, sizeof( client_addr ) ) ) {
			Close();
			return false;
		}
		return true;
	}
public:
	virtual bool Open( uint32_t, uint16_t, bool is_syn = true ) throw()
	{
		return is_syn ? false : false;	// just to avoid warning of compiler
	}
	virtual bool Open( const char_t * addr, uint16_t port, bool is_syn = true ) throw()
	{
		assert( NULL != addr );

		if( is_syn ) {
			// synchronized connection
			return if_OpenSyn( addr, port );
		}else {
			// asynchronized connection
			return false;
		}
	}
	virtual bool Close( void ) throw()
	{
		if( INVALID_SOCKET == m_Socket ) {
			return true;
		}
		SOCKET	tmp = m_Socket;
		m_Socket = INVALID_SOCKET;
		return 0 == closesocket( tmp );
	}
	virtual SyncConnection * GetSyncConnection( void ) throw()
	{
		assert( INVALID_SOCKET != m_Socket );

		IPv4SyncConnection	* p_conn = new IPv4SyncConnection;	// if fail, throw c++ std exception.
		inherited::sif_SetSynConnection( *p_conn, m_Socket, false );
		return p_conn;
	}
	virtual AsyncConnection * GetAsyncConnection( void ) throw()
	{
		return Null< AsyncConnection * >();
	}
public:
	WinSockIPv4Client( void ) throw()
		: inherited(), m_Socket( INVALID_SOCKET )
	{}
	virtual ~WinSockIPv4Client( void ) throw() { Close(); }
protected:
	SOCKET			m_Socket;
};

class WinSockIPv4Server : public WinSockIPv4
{
public:
	typedef	WinSockIPv4	inherited;
protected:
	bool if_OpenSyn( const char_t * addr, uint16_t port ) throw()
	{
		assert( NotNull( addr ) );
		assert( m_nConnection > 0 );

		sockaddr_in		client_addr;

		if( ! Close() ) {
			return false;
		}
		// create socket
		m_Socket = socket( AF_INET, SOCK_STREAM, 0 );
		if( INVALID_SOCKET == m_Socket ) {
			return false;
		}
		// bind
		client_addr.sin_family = AF_INET;
		client_addr.sin_addr.s_addr = inet_addr( addr );
		client_addr.sin_port = htons( port );
		if( SOCKET_ERROR == bind( m_Socket, (SOCKADDR*) & client_addr, sizeof( client_addr ) ) ) {
			Close();
			return false;
		}
		// listen
		return SOCKET_ERROR != listen( m_Socket, int32_t( m_nConnection ) );
	}
public:
	virtual bool Open( uint32_t, uint16_t, bool is_syn = true ) throw()
	{
		return is_syn ? false : false;	// just to avoid warning of compiler
	}
	virtual bool Open( const char_t * addr, uint16_t port, bool is_syn = true ) throw()
	{
		assert( NotNull( addr ) );

		if( is_syn ) {
			// synchronized connection
			return if_OpenSyn( addr, port );
		}else {
			// asynchronized connection
			return false;
		}
	}
	virtual bool Close( void ) throw()
	{
		if( INVALID_SOCKET == m_Socket ) {
			return true;
		}
		SOCKET		tmp = m_Socket;
		m_Socket = INVALID_SOCKET;
		return 0 == closesocket( tmp );
	}
	virtual SyncConnection * GetSyncConnection( void ) throw()
	{
		SOCKET				incoming_socket;
		IPv4SyncConnection	* conn = new IPv4SyncConnection;	// if fail, throw c++ std exception.

		incoming_socket = accept( m_Socket, NULL, NULL );
		if( INVALID_SOCKET == incoming_socket ) {
			delete conn;
			return Null< SyncConnection * >();
		}
		inherited::sif_SetSynConnection( *conn, incoming_socket, true );
		return conn;
	}
	virtual AsyncConnection * GetAsyncConnection( void ) throw()
	{
		return Null< AsyncConnection * >();
	}
public:
	bool SetNumOfConnection( usize_t n ) throw()
	{
		assert( n > 0 );

		if( INVALID_SOCKET != m_Socket ) {
			return false;
		}
		m_nConnection = n;
		return true;
	}
	usize_t GetNumOfConnection( void ) const throw() { return m_nConnection; }
public:
	WinSockIPv4Server( usize_t n_conn = 1 ) throw()
		: inherited(), m_Socket( INVALID_SOCKET ), m_nConnection( n_conn )
	{
		assert( n_conn > 0 );
	}
	virtual ~WinSockIPv4Server( void ) throw() { Close(); }
protected:
	SOCKET		m_Socket;
	size_t		m_nConnection;
};

}	// Tools
}	// PCE_Lib_CurrentCEnvironment
}	// CEnv_Def
}	// PCE_Lib

#endif	// __20081116_DEF_WINSOCKIPV4_H__
